package cn.kgc.mushroommanager.controller;

import cn.kgc.mushroomcommon.api.DataBaseOperationRemoteService;
import cn.kgc.mushroomcommon.api.RedisOperationRemoteService;
import cn.kgc.mushroomcommon.pojo.ResultEntity;
import cn.kgc.mushroomcommon.pojo.User;
import cn.kgc.mushroomcommon.util.CrowdConstant;
import cn.kgc.mushroomcommon.util.CrowdUtils;
import cn.kgc.mushroomcommon.vo.UserSuccessVO;
import cn.kgc.mushroomcommon.vo.UserVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Objects;

@RestController
@RequestMapping("/user/manager")
public class UserController {
    @Value("${code.length}")
    int length;
    @Value("${accessKeyId}")
    String accessKeyId;
    @Value("${secret}")
    String secret;
    @Value("${redis.timeoutMinute}")
    Integer timeoutMinute;
    @Resource
    RedisOperationRemoteService redisOperationRemoteService;
    @Resource
    BCryptPasswordEncoder bCryptPasswordEncoder;
    @Resource
    DataBaseOperationRemoteService dataBaseOperationRemoteService;
    @RequestMapping("/login")
    public ResultEntity<UserSuccessVO> login(
            @RequestParam("account") String account,
            @RequestParam("password") String password) {
        ResultEntity<User> resultEntity = dataBaseOperationRemoteService.retrieveMemberByLoginAcct(account);
        if(ResultEntity.FAILED.equals(resultEntity.getResult())) {
            return ResultEntity.failed(resultEntity.getMessage());
        }
        User user = resultEntity.getData();
        if(user == null) {
            return ResultEntity.failed(CrowdConstant.MESSAGE_LOGIN_FAILED);
        }
        String userpswdDatabase = user.getPassword();
        boolean matcheResult = bCryptPasswordEncoder.matches(password, userpswdDatabase);
        if(!matcheResult) {
            return ResultEntity.failed(CrowdConstant.MESSAGE_LOGIN_FAILED);
        }
        String token = CrowdUtils.generateToken();
        String userId = user.getId() + "";
        ResultEntity<String> resultEntitySaveToken = redisOperationRemoteService.saveNormalStringKeyValue(token, userId, 30);
        if(ResultEntity.FAILED.equals(resultEntitySaveToken.getResult())) {
            return ResultEntity.failed(resultEntitySaveToken.getMessage());
        }
        UserSuccessVO userSuccessVO = new UserSuccessVO();
        BeanUtils.copyProperties(user, userSuccessVO);
        userSuccessVO.setToken(token);
        userSuccessVO.setId(user.getId());
        return ResultEntity.successWithData(userSuccessVO);
    }
    @RequestMapping("/logout")
    public ResultEntity<String> logout(@RequestParam("token") String token) {
        return redisOperationRemoteService.removeByKey(token);
    }

    @RequestMapping("/checkCode")
    public ResultEntity<String> checkCode(@RequestParam("code") String code,@RequestParam("phone") String phone) {
        if(!CrowdUtils.strEffectiveCheck(code)) {
            return ResultEntity.failed(CrowdConstant.MESSAGE_RANDOM_CODE_LENGTH_INVALID);
        }
        if(!CrowdUtils.strEffectiveCheck(phone)) {
            return ResultEntity.failed(CrowdConstant.MESSAGE_PHONE_NUM_INVALID);
        }
        String randomCodeKey = CrowdConstant.REDIS_RANDOM_CODE_PREFIX + phone;
        ResultEntity<String> randomCodeRemoteResultEntity = redisOperationRemoteService.retrieveStringValueByStringKey(randomCodeKey);
        if(ResultEntity.FAILED.equals(randomCodeRemoteResultEntity.getResult())) {
            return randomCodeRemoteResultEntity;
        }
        String randomCodeRemote = randomCodeRemoteResultEntity.getData();
        if(!CrowdUtils.strEffectiveCheck(randomCodeRemote)) {
            return ResultEntity.failed(CrowdConstant.MESSAGE_CODE_NOT_EXISTS);
        }
        if(!Objects.equals(code, randomCodeRemote)) {
            return ResultEntity.failed(CrowdConstant.MESSAGE_CODE_NOT_MATCH);
        }
        ResultEntity<Integer> phoneCount = dataBaseOperationRemoteService.getPhoneCount(phone);
        if(ResultEntity.FAILED.equals(phoneCount.getResult())) {
            return randomCodeRemoteResultEntity;
        }
        Integer phoneCountData = phoneCount.getData();
        if(phoneCountData > 0) {
            return ResultEntity.failed(CrowdConstant.MESSAGE_LOGIN_ACCT_ALREADY_IN_USE);
        }
        return ResultEntity.successNoData();
    }

    @RequestMapping("/register")
    public ResultEntity<String> register(@RequestBody User user) {
        String account = user.getAccount();
        ResultEntity<Integer> loignAcctCountResultEntity = dataBaseOperationRemoteService.retrieveAccountCount(account);
        Integer loignAcctCount = loignAcctCountResultEntity.getData();
        if(loignAcctCount > 0) {
            return ResultEntity.failed(CrowdConstant.MESSAGE_LOGIN_ACCT_ALREADY_IN_USE);
        }
        String password = user.getPassword();
        if(!CrowdUtils.strEffectiveCheck(password)) {
            return ResultEntity.failed(CrowdConstant.MESSAGE_CODE_INVALID);
        }
        password = bCryptPasswordEncoder.encode(password);
        user.setPassword(password);;
        ResultEntity<String> saveMemberRemoteResultEntity = dataBaseOperationRemoteService.register(user);
        return saveMemberRemoteResultEntity;
    }

    @RequestMapping("/send/code")
    public ResultEntity<String> sendCode(@RequestParam("phone") String phone) {
        if(!CrowdUtils.strEffectiveCheck(phone)) {
            return ResultEntity.failed(CrowdConstant.MESSAGE_PHONE_NUM_INVALID);
        }
        String randomCode = CrowdUtils.randomCode(length);
        String normalKey = CrowdConstant.REDIS_RANDOM_CODE_PREFIX + phone;
        ResultEntity<String> resultEntity = redisOperationRemoteService.saveNormalStringKeyValue(normalKey, randomCode, timeoutMinute);

        if(ResultEntity.FAILED.equals(resultEntity.getResult())) {
            return resultEntity;
        }
        try {
            CrowdUtils.sendShortMessage(accessKeyId,secret,randomCode, phone);
            return ResultEntity.successNoData();
        } catch (Exception e) {
            e.printStackTrace();
            return ResultEntity.failed(e.getMessage());
        }
    }

    @RequestMapping("/getUserByPhone")
    public ResultEntity<UserSuccessVO> getUserByPhone(@RequestParam("phone") String phone) {
        ResultEntity<User> resultEntity = dataBaseOperationRemoteService.getUserByPhone(phone);
        if(ResultEntity.FAILED.equals(resultEntity.getResult())) {
            return ResultEntity.failed(resultEntity.getMessage());
        }
        User user = resultEntity.getData();
        if(user == null) {
            return ResultEntity.failed(CrowdConstant.MESSAGE_LOGIN_FAILED);
        }
        String token = CrowdUtils.generateToken();
        String userId = user.getId() + "";
        ResultEntity<String> resultEntitySaveToken = redisOperationRemoteService.saveNormalStringKeyValue(token, userId, 30);
        if(ResultEntity.FAILED.equals(resultEntitySaveToken.getResult())) {
            return ResultEntity.failed(resultEntitySaveToken.getMessage());
        }
        UserSuccessVO userSuccessVO = new UserSuccessVO();
        BeanUtils.copyProperties(user, userSuccessVO);
        userSuccessVO.setToken(token);
        userSuccessVO.setId(user.getId());
        return ResultEntity.successWithData(userSuccessVO);
    }

    @RequestMapping("/checkCodeByPhone")
    public ResultEntity<String> checkCodeByPhone(@RequestParam("code") String code,@RequestParam("phone") String phone) {
        if(!CrowdUtils.strEffectiveCheck(code)) {
            return ResultEntity.failed(CrowdConstant.MESSAGE_RANDOM_CODE_LENGTH_INVALID);
        }
        if(!CrowdUtils.strEffectiveCheck(phone)) {
            return ResultEntity.failed(CrowdConstant.MESSAGE_PHONE_NUM_INVALID);
        }
        String randomCodeKey = CrowdConstant.REDIS_RANDOM_CODE_PREFIX + phone;
        ResultEntity<String> randomCodeRemoteResultEntity = redisOperationRemoteService.retrieveStringValueByStringKey(randomCodeKey);
        if(ResultEntity.FAILED.equals(randomCodeRemoteResultEntity.getResult())) {
            return randomCodeRemoteResultEntity;
        }
        String randomCodeRemote = randomCodeRemoteResultEntity.getData();
        if(!CrowdUtils.strEffectiveCheck(randomCodeRemote)) {
            return ResultEntity.failed(CrowdConstant.MESSAGE_CODE_NOT_EXISTS);
        }
        if(!Objects.equals(code, randomCodeRemote)) {
            return ResultEntity.failed(CrowdConstant.MESSAGE_CODE_NOT_MATCH);
        }
        return ResultEntity.successNoData();
    }
}
